package com.example.traffic_learning;

import global.Util;
import global.global;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Vector;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.CvException;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.core.TermCriteria;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;
import org.opencv.ml.CvANN_MLP;
import org.opencv.ml.CvANN_MLP_TrainParams;

import DTO.SignDTO;
import adapter.GridAdapterTrafficSignSystem;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.text.Html;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;


@SuppressLint("ShowToast")
public class FragDetection extends Fragment {
	private static final int size = 50;
	private double maxArea = 0;
	private int indexMaxArea = -1;
	private int indexSignTypology = -1;
	private ArrayList<String> trainingLabelRedTriangular;
	private ArrayList<String> trainingLabelRedCircle;
	private ArrayList<String> trainingLabelBlueCircle;
	private ExpandableHeightGridView expandableHeightGridView;
	private ArrayList<SignDTO> listSignDTO = new ArrayList<SignDTO>();
	private ImageView iv;
	private CvANN_MLP mlp;
	
	private int output = 4;
	private int atribute = size*2+3;
	
	private AlertDialog.Builder alertDialogBuilder;
	private AlertDialog alertDialog = null;
	public static Mat image;
	private String path = "";
	private static View view;
	private View view1;
	private TextView textResult;
	String dataPath;
	
	private static Activity context;
    private static final int FILE_SELECT_CODE = 0;
    @Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
    	try{
    	BaseLoaderCallback mLoaderCallBack = new BaseLoaderCallback(getActivity().getBaseContext()) {
        	@Override
        	public void onManagerConnected(int status){
        		if(status == LoaderCallbackInterface.SUCCESS){
        			Log.d("OpenCV", "Load success");
        		}else{
        			super.onManagerConnected(status);
        		}
        	}
    	};
    	if (!OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_2, getActivity().getBaseContext(), mLoaderCallBack))
        {
    		
    		Log.e("OpenCV", "Cannot connect to OpenCV Manager");
        }
    	}catch(Exception e){
    		global.isCameraStart = false;
	    	AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
			
			alertDialogBuilder.setMessage("Bạn phải cài đặt OpenCV Manager để sử dụng chức năng này")
					   .setCancelable(false)
					   .setPositiveButton("Đồng ý", new DialogInterface.OnClickListener() {
						
						@Override
						public void onClick(DialogInterface dialog, int which) {
							dialog.dismiss();
							global.isCameraStart = true;
							//getActivity().finish();
							Intent goToMarket = new Intent(Intent.ACTION_VIEW)
						    .setData(Uri.parse("https://play.google.com/store/apps/details?id=org.opencv.engine&hl=vi"));
							startActivity(goToMarket);
						}
					}).setNegativeButton("Trở về", new DialogInterface.OnClickListener() {
						
						@Override
						public void onClick(DialogInterface dialog, int which) {
							dialog.dismiss();
							global.isCameraStart = true;
							getActivity().finish();
						}
					});
			AlertDialog alertDialog = alertDialogBuilder.create();
			alertDialog.show();
    	}
    	
    	
    	super.onCreateView(inflater, container, savedInstanceState);
    	context = getActivity();
    	final String appName = "Traffic Learning";
		final String doccumentPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString();
		dataPath = doccumentPath + "/" + appName;
		File folder = new File(dataPath);
		if (!folder.exists()) {
	        folder.mkdir();
	    }
		InputStream myInput;
		String outFileName;
		OutputStream myOutput;
		byte[] buffer;
		int lenght;
		try{
			//red_circle.xml
			myInput = getActivity().getAssets().open("red_circle.xml");
			outFileName = dataPath + "/red_circle.xml";
			myOutput = new FileOutputStream(outFileName);
			buffer = new byte[512];
			
			while ((lenght = myInput.read(buffer)) > 0){
				myOutput.write(buffer, 0, lenght);
			}
			myOutput.flush();
			myOutput.close();
			myInput.close();
			
			//blue circle.xml
			myInput = getActivity().getAssets().open("blue_circle.xml");
			outFileName = dataPath + "/blue_circle.xml";
			myOutput = new FileOutputStream(outFileName);
			buffer = new byte[512];
			while ((lenght = myInput.read(buffer)) > 0){
				myOutput.write(buffer, 0, lenght);
			}
			myOutput.flush();
			myOutput.close();
			myInput.close();
		}catch(Exception e){
			Log.d("ABCD", e.toString());
		}
    	
    	trainingLabelRedTriangular = new ArrayList<String>();
    	trainingLabelRedTriangular.add("SG0082");
		trainingLabelRedTriangular.add("SG0062");
		trainingLabelRedTriangular.add("SG0063");
		trainingLabelRedTriangular.add("SG0049");
		trainingLabelRedTriangular.add("SG0048");
		
		trainingLabelRedCircle = new ArrayList<String>();
		trainingLabelRedCircle.add("SG0001");
		trainingLabelRedCircle.add("SG0002");
		trainingLabelRedCircle.add("SG0006");
		trainingLabelRedCircle.add("SG0038");
		trainingLabelRedCircle.add("SG0029");
		trainingLabelRedCircle.add("SG0003");
		
		trainingLabelBlueCircle = new ArrayList<String>();
		trainingLabelBlueCircle.add("SG0108");
		trainingLabelBlueCircle.add("SG0118");
		trainingLabelBlueCircle.add("SG0111");
		//trainingLabelBlueCircle.add("SG0112");
        
        view = inflater.inflate(R.layout.activity_detection, container, false);
        view1 = inflater.inflate(R.layout.custom_dialog_sign, container, false);
        iv = (ImageView)view.findViewById(R.id.show_take_picture);
        textResult = (TextView)view.findViewById(R.id.text_view_grid);
        //setContentView(R.layout.activity_detection);
        Button importButton = (Button)view.findViewById(R.id.import_picture);
        importButton.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View arg0) {
				showFileChooser();
				//createANN("/storage/emulated/0/Download/Hoc_Hieu_Lenh", 18, output);
			}
		});
        
        Button cannyButton = (Button)view.findViewById(R.id.canny_picture);
        cannyButton.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				finish();			
				Intent intent = new Intent(getActivity(), CameraActivity.class);
				getActivity().startActivity(intent);
			}
		});
        expandableHeightGridView = (ExpandableHeightGridView)view.findViewById(R.id.expanable_gridview_reconize);
        expandableHeightGridView.setExpanded(true);
        expandableHeightGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> arg0, View arg1, int pos,
					long arg3) {
				alertDialogBuilder = new AlertDialog.Builder(getActivity());
				
				alertDialogBuilder.setCancelable(false)
						   .setPositiveButton("Trở về", new DialogInterface.OnClickListener() {
							
								@Override
								public void onClick(DialogInterface dialog, int which) {
								}
						   });
				TextView textNameSign = (TextView)view1.findViewById(R.id.text_show_name_sign);
				textNameSign.setText(Html.fromHtml( "<strong>Tên</strong>" + "\t\t\t\t\t <strong>:</strong>\t" + listSignDTO.get(pos).getName()));
				TextView textNumber = (TextView)view1.findViewById(R.id.text_number_sign);
				textNumber.setText(Html.fromHtml("<strong>Số hiệu</strong>" + "\t\t\t <strong>:</strong>\t" + listSignDTO.get(pos).getNumber()));
				
				TextView textContent = (TextView)view1.findViewById(R.id.text_sign_detail);
				textContent.setText(Html.fromHtml("<strong>Nội dung</strong>" + "\t\t <strong>:</strong>\t" + listSignDTO.get(pos).getContent()));
				
				TextView textType = (TextView)view1.findViewById(R.id.text_type_sign);
				textType.setText(Html.fromHtml("<strong>Loại</strong>" + "\t\t\t\t\t <strong>:</strong>\t" + listSignDTO.get(pos).getTypeName()));
				Drawable imageDrawable = null;
				try {
					Options opts = new BitmapFactory.Options();
					opts.inDensity = DisplayMetrics.DENSITY_LOW;
					imageDrawable = Drawable.createFromResourceStream(getResources(), null, getActivity().getAssets().open(listSignDTO.get(pos).getImagePath()), null, opts);
				} catch (IOException e) {
					e.printStackTrace();
				}
				ImageView image = (ImageView)view1.findViewById(R.id.image_view_sign_detail);
				image.setImageDrawable(imageDrawable);
				
				LinearLayout myLayout = (LinearLayout)view1.findViewById(R.id.layout_sign_content);
				try{
					alertDialogBuilder.setView(myLayout);
				}catch(Exception e){}
				if(alertDialog == null)
					alertDialog = alertDialogBuilder.create();
				alertDialog.show();
				
			}
		});
        if(!global.imagePath.equals("")){
        	image = new Mat();
			image = Highgui.imread(global.imagePath/*, Imgproc.COLOR_BGR2RGB*/);
			Bitmap bmp;
			BitmapFactory.Options options = new BitmapFactory.Options();
			options.inPreferredConfig = Bitmap.Config.ARGB_8888;
			bmp = BitmapFactory.decodeFile(global.imagePath, options);
			
			ImageView iv = (ImageView)view.findViewById(R.id.show_take_picture);
			iv.setImageBitmap(bmp);
			global.imagePath = "";
			//Utils.bitmapToMat(bmp, image);
			image = scaleImage(image);
			expandableHeightGridView.setAdapter(new GridAdapterTrafficSignSystem(getActivity(), listSignDTO));
			try{
				getSignFromImage();
			}catch(CvException e){
				
			}
        }else{
        	if(global.isCameraStart){
        		global.isCameraStart = false;
        		finish();
		        Intent intent = new Intent(getActivity(), CameraActivity.class);
				getActivity().startActivity(intent);
        	}
        }
        return view;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
    
    private Mat FilterRedPicture(Mat src)
    {
    	Mat temp = src.clone();
    	Mat maskRed1 = new Mat();
    	Mat maskRed2 = new Mat();
    	
    	Imgproc.cvtColor(temp, maskRed1, Imgproc.COLOR_BGR2HSV);
    	maskRed2 = maskRed1.clone();
    	

    	Core.inRange(maskRed1, new Scalar(0,135,15), new Scalar(12,255,255), maskRed1);
    	Core.inRange(maskRed2, new Scalar(165,135,15), new Scalar(180,255,255), maskRed2);
    	
    	Mat des = new Mat();
    	src.copyTo(des, maskRed1);
    	src.copyTo(des, maskRed2);
    	Highgui.imwrite("/storage/emulated/0/Download/result/filter_Red.png", des);
    	return des;
    }
    
    private Mat FilterBluePicture(Mat src)
    {
    	Mat temp = src.clone();
    	Mat maskBlue1 = new Mat();
    	//Mat maskBlue2 = new Mat();
    	
    	Imgproc.cvtColor(temp, maskBlue1, Imgproc.COLOR_BGR2HSV);
    	//maskBlue2 = maskBlue1.clone();
    	
    	Core.inRange(maskBlue1, new Scalar(90, 135, 55), new Scalar(130, 255,255), maskBlue1);
    	//Core.inRange(maskBlue2, new Scalar(90, 65, 100), new Scalar(130, 255,255), maskBlue2);

    	
    	Mat des = new Mat();
    	src.copyTo(des, maskBlue1);
    	//src.copyTo(des, maskBlue2);

    	Highgui.imwrite("/storage/emulated/0/Download/result/filter_Blue.png", des);
    	return des;
    }
    
	private ArrayList<Mat> findRedCircle(Mat src){
    	ArrayList<Mat> listRedCirle = new ArrayList<Mat>();
    	Mat src1 = FilterRedPicture(src);
    	Mat temp1 = src1.clone();
    	Imgproc.cvtColor(temp1, temp1, Imgproc.COLOR_BGR2GRAY);
    	Imgproc.blur(temp1, temp1, new Size(2,2));
    	Imgproc.dilate(temp1, temp1, new Mat(), new Point(-1, -1), 1);
	    Imgproc.erode(temp1, temp1, new Mat(), new Point(-1, -1), 1);
	    Core.addWeighted(temp1, 1.5, temp1, -0.5, 0, temp1);
    	Imgproc.Canny(temp1, temp1, 50, 200);
    	Highgui.imwrite("/storage/emulated/0/Download/result/canny_circle_red.png", temp1);
    	Vector<MatOfPoint> contours = new Vector<MatOfPoint>();
    	Imgproc.findContours(temp1.clone(), contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_NONE, new Point(1, 1));
    	Highgui.imwrite("/storage/emulated/0/Download/result/contours_circle_red.png", temp1);
    	MatOfPoint2f approx = new MatOfPoint2f();
    	
    	int totalLine = 0;
    	for(int i = 0; i < contours.size(); i++){
    		Mat des = src.clone();
    		MatOfPoint tempContour = contours.get(i);
    		MatOfPoint2f newMat = new MatOfPoint2f(tempContour.toArray());
    		Imgproc.approxPolyDP(newMat, approx, ((int)contours.get(i).total())*0.03, true);
    		totalLine = approx.toArray().length;
    		Log.d("Index", "index = " + i);
    		Log.d("Size", "size = "+approx.toList().size());
    		Log.d("Area", "area = "+Math.abs(Imgproc.contourArea(approx)));
    		if((Math.abs(Imgproc.contourArea(approx))<200)){
                Log.i("Opencv", "::onCameraFrame:" + " too small");
                continue;
            }
    		
    		Rect roi2 = Imgproc.boundingRect(contours.get(i));
			Mat des2 = des.submat(roi2);
			Highgui.imwrite("/storage/emulated/0/Download/result/result_circle_red+"+i+".png", des2);
			
    		if(totalLine > 4){
    			double area = Imgproc.contourArea(contours.get(i));
    			Rect roi = Imgproc.boundingRect(contours.get(i));
    			roi.x -= 1.5;
    			roi.y -= 1.5;
    			double radius = roi.width/2;
    			
    			if(Math.abs(1 - ((double)roi.width / (double)roi.height)) <= 0.3 && Math.abs(1 - (area / (Math.PI * Math.pow(radius, 2)))) <= 0.3){
    				Log.d("Hinh tron", "co");
    				Imgproc.drawContours(des.clone(), contours, i, new Scalar(255), 5);
    				Mat candidate = des.submat(roi);
    				Highgui.imwrite("/storage/emulated/0/Download/result/result_circle_cat_xen+"+i+".png", candidate);
    				if(Math.abs(Imgproc.contourArea(approx)) > maxArea){
    		    	    Mat mask=new Mat(roi.size(),candidate.type(), new Scalar(0,0,0));
    		    	    Highgui.imwrite("/storage/emulated/0/Download/result/mask+"+i+".png", mask);    	    
    		            Imgproc.drawContours(mask, contours, i, new Scalar(255,255,255), -1 , 8, new Mat(), 0, new Point(-(roi.x +2),-(roi.y+1.5)));
    		            Mat roi1=new Mat(candidate.size(), candidate.type(), new Scalar(255,255,255));
    		    	    candidate.copyTo(roi1, mask);
    		    	    listRedCirle.add(roi1);
    					Highgui.imwrite("/storage/emulated/0/Download/result/result_red_circle+"+i+".png", roi1);
    					maxArea = Math.abs(Imgproc.contourArea(approx));
    					indexSignTypology = 1;
    					indexMaxArea++;
    				}
    				
    			}
    			
    		}    	
    	}
    	return listRedCirle;
    }
    
	private ArrayList<Mat> findBlueShape(Mat src){
    	ArrayList<Mat> listBlueShape = new ArrayList<Mat>();
    	Mat src1 = FilterBluePicture(src);
    	Mat temp1 = src1.clone();
    	Imgproc.cvtColor(temp1, temp1, Imgproc.COLOR_BGR2GRAY);
    	Imgproc.blur(temp1, temp1, new Size(2,2));
    	Imgproc.dilate(temp1, temp1, new Mat(), new Point(-1, -1), 1);
	    Imgproc.erode(temp1, temp1, new Mat(), new Point(-1, -1), 1);
	    Core.addWeighted(temp1, 1.5, temp1, -0.5, 0, temp1);
	    Highgui.imwrite("/storage/emulated/0/Download/result/result_blue_pre_canny.png", temp1);
	    Imgproc.Canny(temp1, temp1, 50, 200);
    	Highgui.imwrite("/storage/emulated/0/Download/result/result_blue_canny.png", temp1);
    	Vector<MatOfPoint> contours = new Vector<MatOfPoint>();
    	Imgproc.findContours(temp1.clone(), contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_NONE, new Point(1, 1));
    	MatOfPoint2f approx = new MatOfPoint2f();
    	
    	int totalLine = 0;
    	Log.d("ABCD", "Size contours: " + contours.size());
    	for(int i = 0; i < contours.size(); i++){
    		Mat des = src.clone();
    		MatOfPoint tempContour = contours.get(i);
    		MatOfPoint2f newMat = new MatOfPoint2f(tempContour.toArray());
    		Imgproc.approxPolyDP(newMat, approx, ((int)contours.get(i).total())*0.03, true);
    		totalLine = approx.toArray().length;
    		Log.d("Size", "size = "+approx.toList().size());
    		Log.d("Area", "area = "+Math.abs(Imgproc.contourArea(approx)));
    		if((Math.abs(Imgproc.contourArea(approx))<200) ){
                Log.i("Opencv", "::onCameraFrame:" + " too small");
                continue;
            }
    		
    		Rect roi2 = Imgproc.boundingRect(contours.get(i));
			Mat des2 = des.submat(roi2);
			Highgui.imwrite("/storage/emulated/0/Download/result/result_circle_blue+"+i+".png", des2);
    		
			if(approx.toArray().length >= 4 && approx.toArray().length <= 6){
    			ArrayList<Double> cos = new ArrayList<Double>();
    			for(int j = 2; j <= totalLine; j++){
    				cos.add(angle(approx.toArray()[j%totalLine], approx.toArray()[j-2], approx.toArray()[j-1]));
    			}
    			Collections.sort(cos);
    			double minCos = cos.get(0);
    			double maxCos = cos.get(cos.size() - 1);
    			
    			if(totalLine == 4 && minCos >= -0.1 && maxCos <=0.3){
    				Log.d("Hinh chu nhat", "co");
    				Rect roi = Imgproc.boundingRect(contours.get(i));
    				Mat candidate = des.submat(roi);
    				
    				if(Math.abs(Imgproc.contourArea(approx)) > maxArea){
    		    	    Mat mask=new Mat(roi.size(),candidate.type(), new Scalar(0,0,0));        	    
    		            Imgproc.drawContours(mask, contours, i, new Scalar(255,255,255), -1 , 8, new Mat(), 0, new Point(-roi.x,-roi.y));
    		            Mat roi1=new Mat(candidate.size(), candidate.type(), new Scalar(255,255,255));
    		    	    candidate.copyTo(roi1, mask);
    		    	    listBlueShape.add(roi1);
    					Highgui.imwrite("/storage/emulated/0/Download/result_blue_Rectangular+"+i+".png", roi1);
    					maxArea = Math.abs(Imgproc.contourArea(approx));
    					indexSignTypology = 3;
    					indexMaxArea++;
    				}
    					
    			}else if(totalLine == 6 && minCos >= -0.55 && maxCos <= -0.45){
    				Log.d("Hinh luc giac", "co");
    				Imgproc.drawContours(des.clone(), contours, i, new Scalar(255), 5);
    				Rect roi = Imgproc.boundingRect(contours.get(i));
    				Mat candidate = des.submat(roi);
    				if(Math.abs(Imgproc.contourArea(approx)) > maxArea){
    		    	    Mat mask=new Mat(roi.size(),candidate.type(), new Scalar(0,0,0));    	    
    		            Imgproc.drawContours(mask, contours, i, new Scalar(255,255,255), -1 , 8, new Mat(), 0, new Point(-roi.x,-roi.y));
    		            Mat roi1=new Mat(candidate.size(), candidate.type(), new Scalar(255,255,255));
    		    	    candidate.copyTo(roi1, mask);
    		    	    listBlueShape.add(roi1);
    					maxArea = Math.abs(Imgproc.contourArea(approx));
    					indexSignTypology = 3;
    					indexMaxArea++;
    				}
    			}
    		}    	
			
    		if(totalLine > 4){
    			double area = Imgproc.contourArea(contours.get(i));
    			Rect roi = Imgproc.boundingRect(contours.get(i));
    			double radius = roi.width/2;

    			if(Math.abs(1 - ((double)roi.width / (double)roi.height)) <= 0.3 && Math.abs(1 - (area / (Math.PI * Math.pow(radius, 2)))) <= 0.3){
    				Log.d("Hinh tron", "co");
    				Imgproc.drawContours(des.clone(), contours, i, new Scalar(255), 5);
    				Mat candidate = des.submat(roi);
    				if(Math.abs(Imgproc.contourArea(approx)) > maxArea){
    		    	    Mat mask=new Mat(roi.size(),candidate.type(), new Scalar(0,0,0));     	    
    		            Imgproc.drawContours(mask, contours, i, new Scalar(255,255,255), -1 , 8, new Mat(), 0, new Point(-roi.x,-roi.y));
    		            Mat roi1=new Mat(candidate.size(), candidate.type(), new Scalar(255,255,255));
    		    	    candidate.copyTo(roi1, mask);
    					listBlueShape.add(roi1);
    					Highgui.imwrite("/storage/emulated/0/Download/result/result_blue_circle+"+i+".png", roi1);
    					maxArea = Math.abs(Imgproc.contourArea(approx));
    					indexSignTypology = 2;
    					indexMaxArea++;
    				}
    				
    			}
    			
    		}    	
    	}
    	return listBlueShape;
    }
    
	/*private ArrayList<Mat> findBlueRectangular(Mat src){
    	ArrayList<Mat> listBlueRectangular = new ArrayList<Mat>();
    	Mat src1 = FilterBluePicture(src);
    	Mat temp1 = src1.clone();
    	Imgproc.cvtColor(temp1, temp1, Imgproc.COLOR_BGR2GRAY);
    	Imgproc.blur(temp1, temp1, new Size(2,2));
	    //Imgproc.GaussianBlur(temp1, temp1, new Size(0, 0), 3);
	    Core.addWeighted(temp1, 1.5, temp1, -0.5, 0, temp1);
    	Imgproc.Canny(temp1, temp1, 50, 200);
    	Vector<MatOfPoint> contours = new Vector<MatOfPoint>();
    	Imgproc.findContours(temp1.clone(), contours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_NONE, new Point(1, 1));
    	MatOfPoint2f approx = new MatOfPoint2f();
    	
    	int totalLine = 0;
    	for(int i = 0; i < contours.size(); i++){
    		Mat des = src.clone();
    		MatOfPoint tempContour = contours.get(i);
    		MatOfPoint2f newMat = new MatOfPoint2f(tempContour.toArray());
    		Imgproc.approxPolyDP(newMat, approx, ((int)contours.get(i).total())*0.05, true);
    		totalLine = approx.toArray().length;
    		MatOfPoint points=new MatOfPoint(approx.toArray());
    		Log.d("Size", "size = "+approx.toList().size());
    		Log.d("Area", "area = "+Math.abs(Imgproc.contourArea(approx)));
    		if((Math.abs(Imgproc.contourArea(approx))<200) || !Imgproc.isContourConvex(points)){
                Log.i("Opencv", "::onCameraFrame:" + " too small");
                continue;
            }
    		if(approx.toArray().length >= 4 && approx.toArray().length <= 6){
    			ArrayList<Double> cos = new ArrayList<Double>();
    			for(int j = 2; j <= totalLine; j++){
    				cos.add(angle(approx.toArray()[j%totalLine], approx.toArray()[j-2], approx.toArray()[j-1]));
    			}
    			Collections.sort(cos);
    			double minCos = cos.get(0);
    			double maxCos = cos.get(cos.size() - 1);
    			
    			if(totalLine == 4 && minCos >= -0.1 && maxCos <=0.3){
    				Log.d("Hinh chu nhat", "co");
    				//Imgproc.drawContours(des.clone(), contours, i, new Scalar(255), 5);
    				Rect roi = Imgproc.boundingRect(contours.get(i));
    				Mat candidate = des.submat(roi);
    				
    				if(Math.abs(Imgproc.contourArea(approx)) > maxArea){
    					//Get mask of contour
    		    	    Mat mask=new Mat(roi.size(),candidate.type(), new Scalar(0,0,0));
    		    	    //Draw contour        	    
    		            Imgproc.drawContours(mask, contours, i, new Scalar(255,255,255), -1 , 8, new Mat(), 0, new Point(-roi.x,-roi.y));
    		            Mat roi1=new Mat(candidate.size(), candidate.type(), new Scalar(255,255,255));
    		    	    candidate.copyTo(roi1, mask);
    					listBlueRectangular.add(roi1);
    					Highgui.imwrite("/storage/emulated/0/Download/result_blue_Rectangular+"+i+".png", roi1);
    					maxArea = Math.abs(Imgproc.contourArea(approx));
    					indexSignTypology = 3;
    					indexMaxArea++;
    				}
    					
    			}else if(totalLine == 6 && minCos >= -0.55 && maxCos <= -0.45){
    				Log.d("Hinh luc giac", "co");
    				Imgproc.drawContours(des.clone(), contours, i, new Scalar(255), 5);
    				Rect roi = Imgproc.boundingRect(contours.get(i));
    				Mat candidate = des.submat(roi);
    				if(Math.abs(Imgproc.contourArea(approx)) > maxArea){
    					//Get mask of contour
    		    	    Mat mask=new Mat(roi.size(),candidate.type(), new Scalar(0,0,0));
    		    	    //Draw contour        	    
    		            Imgproc.drawContours(mask, contours, i, new Scalar(255,255,255), -1 , 8, new Mat(), 0, new Point(-roi.x,-roi.y));
    		            Mat roi1=new Mat(candidate.size(), candidate.type(), new Scalar(255,255,255));
    		    	    candidate.copyTo(roi1, mask);
    					listBlueRectangular.add(roi1);
    					maxArea = Math.abs(Imgproc.contourArea(approx));
    					indexSignTypology = 3;
    					indexMaxArea++;
    				}
    			}
    		}    	
    	}
    	return listBlueRectangular;
    }*/
    
	/*private ArrayList<Mat> findRedTriangular(Mat src){
    	ArrayList<Mat> listRedTriangular = new ArrayList<Mat>();
    	
    	Mat src1 = FilterRedPicture(src);
    	
    	Highgui.imwrite("/storage/emulated/0/Download/result/result_1.png", src1);
    	Mat temp1 = src1.clone();
    	Imgproc.cvtColor(temp1, temp1, Imgproc.COLOR_BGR2GRAY);
    	//Imgproc.dilate(temp1, temp1, new Mat(), new Point(-1, -1), 3);
	    //Imgproc.erode(temp1, temp1, new Mat(), new Point(-1, -1), 3);
	    Imgproc.blur(temp1, temp1, new Size(2,2));
	    //Imgproc.GaussianBlur(temp1, temp1, new Size(0, 0), 3);
	    Core.addWeighted(temp1, 1.5, temp1, -0.5, 0, temp1);
	    Highgui.imwrite("/storage/emulated/0/Download/result/result_red_pre_canny.png", temp1);
    	Imgproc.Canny(temp1, temp1, 100, 150);
    	Highgui.imwrite("/storage/emulated/0/Download/result/result_red_canny.png", temp1);
    	Vector<MatOfPoint> contours = new Vector<MatOfPoint>();
    	Imgproc.findContours(temp1, contours, new Mat(), Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE);
    	Highgui.imwrite("/storage/emulated/0/Download/result/result_red_contour.png", temp1);
    	MatOfPoint2f approx = new MatOfPoint2f();
    	
    	int totalLine = 0;
    	for(int i = 0; i < contours.size(); i++){
    		Mat abc = contours.get(i);
    		Mat des = src.clone();
    		MatOfPoint tempContour = contours.get(i);
    		MatOfPoint2f newMat = new MatOfPoint2f(tempContour.toArray());
    		//Imgproc.approxPolyDP(newMat, approx, ((int)contours.get(i).total())*0.15, true);
    		
    		
    		List<Point> points1=new ArrayList<Point>();
	    	int num = (int) abc.total(); 
	    	int temp[] = new int[num*2]; 
	    	abc.get(0, 0, temp);
	    	
	    	for(int j=0;j<num*2;j=j+2)
	    		points1.add(new Point(temp[j], temp[j+1]));
    		
    		MatOfPoint2f matOfPoint = new MatOfPoint2f();
    		matOfPoint.fromList(points1);
    		Imgproc.approxPolyDP(newMat, approx, Imgproc.arcLength(matOfPoint, true)* 0.08, true);
    		//Imgproc.approxPolyDP(newMat, approx, ((int)contours.get(i).total())*0.5, true);
    		totalLine = approx.toArray().length;
    		MatOfPoint points=new MatOfPoint(approx.toArray());
    		Log.d("Index", i + "");
    		Log.d("Size", "size = "+approx.toList().size() + "|" + approx.toArray().length);
    		Log.d("Area", "area = "+Math.abs(Imgproc.contourArea(approx)) + "|" + Imgproc.contourArea(approx));
    		
			if(i != (contours.size() - 1)){
				if((Math.abs(Imgproc.contourArea(tempContour.t())) < 200) || !Imgproc.isContourConvex(points)){
	                Log.i("Opencv", "::onCameraFrame:" + " too small");
	                continue;
	            }
    		}
			
    		if(totalLine == 3){
				Log.d("Tam Giac", "co");
				Imgproc.drawContours(des.clone(), contours, i, new Scalar(255), 5);
				Rect roi = Imgproc.boundingRect(contours.get(i));
				Mat candidate = des.submat(roi);
				Log.d("ABCD", "chua co loi 1");
				if(Math.abs(Imgproc.contourArea(approx)) > maxArea){
					Log.d("ABCD", "vao duoc");
					//Get mask of contour
		    	    Mat mask=new Mat(roi.size(),candidate.type(), new Scalar(0,0,0));
		    	    //Draw contour        	    
		            Imgproc.drawContours(mask, contours, i, new Scalar(255,255,255), -1 , 8, new Mat(), 0, new Point(-roi.x,-roi.y));
		            Mat roi1=new Mat(candidate.size(), candidate.type(), new Scalar(255,255,255));
		    	    candidate.copyTo(roi1, mask);
					listRedTriangular.add(roi1);
					maxArea = Math.abs(Imgproc.contourArea(approx));
					indexSignTypology = 4;
					indexMaxArea++;
				}else{
					Log.d("ABCD", "ko vao duoc");
				}
			}   	
    	}
    	return listRedTriangular;
    }*/
    
    private double angle(Point pt1, Point pt2, Point pt0){
    	double dx1 = pt1.x - pt0.x;
        double dy1 = pt1.y - pt0.y;
        double dx2 = pt2.x - pt0.x;
        double dy2 = pt2.y - pt0.y;
        return (dx1*dx2 + dy1*dy2)/Math.sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
    }

    private void initNetwork(Mat src){
    	Log.d("ABCD", "init network");
    	listSignDTO = new ArrayList<SignDTO>();
    	ArrayList<String> listOutput = new ArrayList<String>();
    	double minRate = 1;
    	Highgui.imwrite(dataPath +"/result.png", src);
    	expandableHeightGridView.setAdapter(new GridAdapterTrafficSignSystem(getActivity(), listSignDTO));
    	try{
    		mlp = new CvANN_MLP();
    		switch(indexSignTypology){
    		case 1:
    			mlp.load(dataPath + "/red_circle.xml");
    			listOutput.addAll(trainingLabelRedCircle);
    			minRate = 0.6;
    			break;
    		case 2:
    			mlp.load(dataPath + "/blue_circle.xml");
    			listOutput.addAll(trainingLabelBlueCircle);
    			minRate = 0.6;
    			break;
    		case 3:
    			mlp.load(dataPath + "/rectangular.xml");
    			break;
    		}
    		//for(int t = 0; t <= 1; t++){
	        	Mat image1 = Highgui.imread(dataPath + "/result.png");
	        	//if(t==1){
	        		Imgproc.blur(image1, image1, new Size(1,1));
	        	//}
	        	Imgproc.resize(image1, image1, new Size(size,size));
	        	Bitmap bm = Bitmap.createBitmap(image1.cols(), image1.rows(), Bitmap.Config.RGB_565);
	    		Utils.matToBitmap(image1, bm);
	        	Mat test = new Mat(1, atribute, CvType.CV_32F);
	        	try {
	    			double[] temp = Util.toData(bm, size);
	    			for(int j = 0; j < temp.length; j++){
	    				test.put(0, j, temp[j]);
	    			}
	    		} catch (Exception e) {
	    			e.printStackTrace();
	    		}
	        	Mat result = new Mat(1, output, CvType.CV_32F);
	        	mlp.predict(test, result);
	    		
	        	double value = 0;
	        	OutputPredict[] arrOutput = new OutputPredict[listOutput.size()];
	        	for(int i = 0; i < listOutput.size(); i++){
	        		value = result.get(0, i)[0];
	        		arrOutput[i]= new OutputPredict(value, listOutput.get(i));
	        		Log.d("ABCD", "Truoc sort: " + listOutput.get(i) + ": " + f(value));		
	    		}
	        	for(int i = 0; i < arrOutput.length; i++){
	        		for(int j = i + 1; j < arrOutput.length - 1; j++){
	        			if(arrOutput[j].getValue() > arrOutput[i].getValue()){
	        				OutputPredict temp = arrOutput[i];
	        				arrOutput[i] = arrOutput[j];
	        				arrOutput[j] = temp;
	        			}
	        		}
	        	}
	        	for(int i = 0; i < arrOutput.length; i++){
	        		Log.d("ABCD", "Sau sort: " + arrOutput[i].getLable() + ": " + f(arrOutput[i].getValue()));
	        		if(f(arrOutput[i].getValue())>= minRate){
	        			listSignDTO.add(SignDTO.getSignByID(getActivity(), arrOutput[i].getLable()));
	        		}
	        	}
	        	
	    		if(listSignDTO.size() > 0){
	    			textResult.setText("Danh sách kết quả");
	    			expandableHeightGridView.setAdapter(new GridAdapterTrafficSignSystem(getActivity(), listSignDTO));
	    			//break;
	    		}else{
	    			textResult.setText("Không nhận diện thấy kết quả phù hợp. Vui lòng chọn lại hình khác hay chụp lại hình");
	    		}
    		//}
    	}
    	catch(Exception e)
    	{
    		Log.i("MainActivity.Class",e.toString());
    	}
    }
    
	private void showFileChooser() {
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT); 
        intent.setType("image/*"); 
        intent.addCategory(Intent.CATEGORY_OPENABLE);

        try {
            startActivityForResult(
                    Intent.createChooser(intent, "Select a File to Upload"),
                    FILE_SELECT_CODE);
        } catch (android.content.ActivityNotFoundException ex) {
            // Potentially direct the user to the Market with a Dialog
            Toast.makeText(getActivity(), "Please install a File Manager.", 
                    Toast.LENGTH_SHORT).show();
        }
    }
    
    @SuppressWarnings("static-access")
	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case FILE_SELECT_CODE:
            if (resultCode == getActivity().RESULT_OK) {

                Uri uri = data.getData();

                path = "";
                try {
                	path = getPath(getActivity(), uri);
                	image = new Mat();
					image = Highgui.imread(path/*, Imgproc.COLOR_BGR2RGB*/);
					Bitmap bmp;
					BitmapFactory.Options options = new BitmapFactory.Options();
					options.inPreferredConfig = Bitmap.Config.ARGB_8888;
					bmp = BitmapFactory.decodeFile(path, options);
					Log.d("ABCD", path);
					iv.setImageBitmap(bmp);
					image = scaleImage(image);
					try{
						getSignFromImage();
					}catch(CvException e){
						Log.d("ABCD", e.toString());
					}
                } catch (URISyntaxException e) {
                	e.printStackTrace();
                }
            }
            break;
        }
        super.onActivityResult(requestCode, resultCode, data);
    }
    
    public static String getPath(Context context, Uri uri) throws URISyntaxException {
        if ("content".equalsIgnoreCase(uri.getScheme())) {
            String[] projection = { "_data" };
            Cursor cursor = null;

            try {
                cursor = context.getContentResolver().query(uri, projection, null, null, null);
                int column_index = cursor.getColumnIndexOrThrow("_data");
                if (cursor.moveToFirst()) {
                    return cursor.getString(column_index);
                }
            } catch (Exception e) {
            }
        }
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        }

        return null;
    }


    private void getSignFromImage(){
    	Log.d("ABCD", "vao duoc getSignFromImage");
    	maxArea = 0;
    	indexMaxArea = -1;
    	Mat src = image.clone();
    	textResult.setText("Đang xử lý ảnh...");
    	Log.d("ABCD", textResult.getText().toString());
    	listSignDTO = new ArrayList<SignDTO>();
		expandableHeightGridView.setAdapter(new GridAdapterTrafficSignSystem(getActivity(), listSignDTO));
		//ArrayList<Mat> listRedTriangular = findRedTriangular(src.clone());
		ArrayList<Mat> listRedCircle = findRedCircle(src.clone());
		ArrayList<Mat> listBlueShape = findBlueShape(src.clone());
		Log.d("ABCD", "Chua co loi");
		//ArrayList<Mat> listBlueRectangular = findBlueRectangular(src.clone());
		ArrayList<Mat> listMat = new ArrayList<Mat>();
		//listMat.addAll(listRedTriangular);
		listMat.addAll(listRedCircle);
		listMat.addAll(listBlueShape);
		//listMat.addAll(listBlueRectangular);
		Mat abc = null;
		if(listMat.size() > 0){
			try{
				abc = listMat.get(indexMaxArea);
				indexMaxArea = -1;
			}catch(Exception e){
				abc = listMat.get(0);
				indexMaxArea = -1;
			}
		}
		if(abc != null){
			final String appName = "Traffic Learning";
			final String galleryPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString();
			final String albumPath = galleryPath + "/" + appName;
			File folder = new File(albumPath);
			if (!folder.exists()) {
		        folder.mkdir();
		    }
			Highgui.imwrite(albumPath+"/abc.png", abc);
			Bitmap bmp;
			BitmapFactory.Options options = new BitmapFactory.Options();
			options.inPreferredConfig = Bitmap.Config.ARGB_8888;
			bmp = BitmapFactory.decodeFile(albumPath+"/abc.png", options);
			iv.setImageBitmap(bmp);
			
			initNetwork(abc);
		}else{
			textResult.setText("Chương trình không tìm thấy biển báo nào trong hình");
			listSignDTO = new ArrayList<SignDTO>();
			expandableHeightGridView.setAdapter(new GridAdapterTrafficSignSystem(getActivity(), listSignDTO));
		}
    }
    
	private void createANN(String samplesImagePath, int numOfImage, int numOfClasses){
    	Mat trainingData = new Mat(numOfImage*numOfClasses, atribute, CvType.CV_32F);
    	trainingLabelRedTriangular = new ArrayList<String>();
    	trainingLabelRedCircle = new ArrayList<String>();
    	trainingLabelBlueCircle = new ArrayList<String>();
    	//Mat outputs = new Mat(numOfImage*numOfClasses, output, CvType.CV_32F);
    	Mat outputs = new Mat(numOfImage*numOfClasses, output, CvType.CV_32F);
    	for(int i = 0; i < numOfClasses; i++){ 
    		for(int sample = 0; sample < numOfImage; sample++){
	    			String imagePath = samplesImagePath +"/" + (i+1) + "/img("+(sample+1)+").png";
	    			Mat image = Highgui.imread(imagePath);
	    			Imgproc.resize(image, image, new Size(size, size));
	    			
	    			Bitmap bm = Bitmap.createBitmap(image.cols(), image.rows(), Bitmap.Config.RGB_565);
					Utils.matToBitmap(image, bm);
	    			try {
						double[] temp = Util.toData(bm, size);
						for(int j = 0; j< temp.length; j++){
							trainingData.put((i)*(numOfImage) + (sample), j, temp[j]);
						}	
						outputs.put((i)*(numOfImage) + (sample), i, 1);
					} catch (Exception e) {
						e.printStackTrace();
					}    			
    			}    		
    		}
  
    	trainingLabelRedTriangular.add("SG0082");
		trainingLabelRedTriangular.add("SG0062");
		trainingLabelRedTriangular.add("SG0063");
		trainingLabelRedTriangular.add("SG0049");
		trainingLabelRedTriangular.add("SG0048");
				
		trainingLabelRedCircle.add("SG0001");
		trainingLabelRedCircle.add("SG0002");
		trainingLabelRedCircle.add("SG0006");
		trainingLabelRedCircle.add("SG0038");
		trainingLabelRedCircle.add("SG0029");
		trainingLabelRedCircle.add("SG0003");
		
		trainingLabelBlueCircle.add("SG0108");
		trainingLabelBlueCircle.add("SG0118");
		trainingLabelBlueCircle.add("SG0111");
		trainingLabelBlueCircle.add("SG0112");
		
    	Mat layers = new Mat(3, 1, CvType.CV_32S);
    	layers.put(0, 0, atribute);;
    	layers.put(1, 0, 80);
    	layers.put(2, 0, output);
    	CvANN_MLP mlp = new CvANN_MLP();
    	mlp.create(layers, CvANN_MLP.SIGMOID_SYM,  1, 1);
    	CvANN_MLP_TrainParams params = new CvANN_MLP_TrainParams();
    	params.set_term_crit(new TermCriteria(TermCriteria.EPS + TermCriteria.MAX_ITER, 1000, 0.0001));
    	params.set_train_method(CvANN_MLP_TrainParams.BACKPROP);
    	params.set_bp_dw_scale(0.01);
    	params.set_bp_moment_scale(0.5);
    	int iterations = 0;
    	int incorrect = 100;
    	int minIncorrect = 100;
    	int abc = 0;
    	//Mat weight = new Mat();
    	while(incorrect > 0){
    		incorrect = 0;
    		iterations = mlp.train(trainingData, outputs, new Mat(), new Mat(), params, CvANN_MLP.UPDATE_WEIGHTS & CvANN_MLP.NO_INPUT_SCALE & CvANN_MLP.NO_OUTPUT_SCALE);
    		Log.d("ABCD", "abc = "+ abc);
    		Log.d("ABCD", "iterations = "+ iterations);
    		
    		
        	
        	for(int i = 1; i <= numOfClasses; i++){
        		for(int j = 1; j <= numOfImage; j++){
        			Mat image1 = Highgui.imread(samplesImagePath + "/"+i+"/img("+j+").png");

        	    	Imgproc.resize(image1, image1, new Size(size,size));
        	    	Bitmap bm = Bitmap.createBitmap(image1.cols(), image1.rows(), Bitmap.Config.RGB_565);
        			Utils.matToBitmap(image1, bm);
        	    	Mat test = new Mat(1, atribute, CvType.CV_32F);
        	    	try {
        				double[] temp = Util.toData(bm, size);
        				for(int t = 0; t < temp.length; t++){
        					test.put(0, t, temp[t]);
        				}
        			} catch (Exception e) {
        				e.printStackTrace();
        			}
        	    	Mat result = new Mat(1, output, CvType.CV_32F);
        	    	mlp.predict(test, result);
        	    	
        	    	int index = 0;
        	    	double value = 0;
        	    	double maxValue = result.get(0, 0)[0];
        	    	for(int t = 0; t < output; t++){
        	    		value = result.get(0, t)[0];
        	    		if(value > maxValue){
        	    			maxValue = value;
        	    			index = t;
        	    		}
        	    		
        	    	}
        	    	
        	    	
        	    	if(index != i - 1){
        	    		incorrect++;
        	    	}
        		}
        		
        	}
        	if(minIncorrect > incorrect){
        		minIncorrect = incorrect;

        	}
        	Log.d("ABCD", "Error= " + incorrect + " Min= " + minIncorrect);
        	if(iterations == 1000){
    			break;
    		}
    		if(abc>1000){
    			break;
    		}
        	abc++;
    	}
    	mlp.save("/storage/emulated/0/Download/blue_circle.xml");
    	mlp.save("/data/data/com.example.traffic_learning/databases/blue_circle.xml");
    	
    }

	public double f(double x) {
		return (1 / (1 + Math.exp(-x)));
	}
	
	public static void startCamera(){
		finish();
		Intent intent = new Intent(context, CameraActivity.class);
		context.startActivity(intent);
	}
	
	public static void finish(){
		context.finish();
	}
	
	public class OutputPredict{
		private double value;
		private String lable;
		public OutputPredict() {
		}
		public OutputPredict(double value, String lable) {
			this.value = value;
			this.lable = lable;
		}
		
		public double getValue() {
			return value;
		}
		public void setValue(double value) {
			this.value = value;
		}
		public String getLable() {
			return lable;
		}
		public void setLable(String lable) {
			this.lable = lable;
		}	
	}
	private Mat scaleImage(Mat mat){
		Mat result = mat.clone();
		int width = mat.width();
		int height = mat.height();
		Log.d("ABCD", "Truoc resize: "+width +"  "+ height);
		if(width > 1000){
			width = 1000;
			height = (mat.height() * 1000)/mat.width();
			Imgproc.resize(result, result, new Size(width, height));
		}
		Log.d("ABCD", "Truoc resize: "+width +"  "+ height);
		return result;
	}
}

